(function($){
	
	/**
	 * deepCopy()
	 *		make a copy of an object, and all of its constituent parts
	 */
	deepCopy = function(x) {
			if (	( x == null ) ||
					( typeof x == 'function' ) ||
					( ! ( x instanceof Object ) ) ) {
				return x;
			} else if ( $.isArray( x ) ) {
				var results = [];
				for ( var i = 0 ; i < x.length ; i++ ) {
					results.push( deepCopy( x[i] ) );
				}
				return results;
			} else {
				var results = ( x.constructor ? new x.constructor() : {} );
				for ( var i in x ) {
					results[i] = deepCopy( x[i] );
				}
				return results;
			}	
		};

	/**
	 * merge()
	 *		merge two objects into one.  Like $.extend(true,...), but
	 *		with a little more intelligent behavior, such as combining
	 *		contents of arrays in source and target into one big array
	 */
	merge = function() {
			var arg,key,value,old,base,a,b;
			var args = Array.prototype.slice.call(arguments);
			base = args.shift();
			if ( base == null ) base = {};
			while ( args.length > 0 ) {
				arg = args.shift();
				if ( arg != null ) {
					if ( $.isArray( arg ) ) {
						args = arg.concat(args);
					} else if ( typeof arg == 'string' ) {
						if ( ! ( base.hasOwnProperty(arg) ) ) {
							base[arg] = null;
						}
					} else if ( ! (arg instanceof Object ) ) {
						console.log( 'WTF?' );
						console.log( arg );
						throw( 'what are you trying to do?' )
					} else {
						for ( key in arg ) {
							value = arg[key];
							if ( value != null ) {
								value = arg[key];
								if ( $.isArray( value ) ) {
									if ( ! $.isArray( base[key] ) ) {
										old = base[key];
										base[key] = [];
										if ( old != null ) base[key].push( old );
									}
									base[key] = base[key].concat( deepCopy( value ) );
								} else if (	( ! base.hasOwnProperty(key) ) || 
											base[key] == null ||
											! ( base[key] instanceof Object ) ) {
									base[key] = ( value instanceof Object ? deepCopy( value ) : value );
								} else if ( $.isArray( base[key] ) ) {
									base[key].push( deepCopy( value ) );
								} else if ( base[key] instanceof Object ) {
									if ( ! ( value instanceof Object ) ) {
										if ( $.isFunction( base[key] ) ) {
											base[key] = value;
										} else {
											base[key][value] = null;
										}										
									} else {
										if ( $.isFunction( value ) ) {
											base[key] = value;
										} else if ( value.constructor && ! $.isFunction( base[key] ) ) {
											var target = new value.constructor();
											for ( i in base[key] ) {
												target[i] = merge( base[key][i], value[i] );
											}
											for ( i in value ) {
												if ( ! base[key].hasOwnProperty[i] ) {
													target[i] = deepCopy( value[i] );
												}
											}
											base[key] = target;
										} else {
											merge( base[key], value );
										}
									}
								} else {
									console.log( 'what did I miss?' );
									console.log( base[key] );
									console.log( value );
								}
							}
						}
					}
				}
			}
			return base;
		};

	/**
	 * a shallow, and therefore faster version of merge
	 */
	mergeFast = function() {
			var i,key,value;
			var base = arguments[0];
			for ( i = 1 ; i < arguments.length ; i++ ) {
				for ( key in arguments[i] ) {
					if ( ( value = arguments[i][key] ) != null ) {
						base[key] = value;
					}
				}
			}
			return base;
		};
	
	// copy of jquery 1.3.2 version of extend, for comparative profiling purposes
	jQuery_extend = function() {
			// copy reference to target object
			var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
		
			// Handle a deep copy situation
			if ( typeof target === "boolean" ) {
				deep = target;
				target = arguments[1] || {};
				// skip the boolean and the target
				i = 2;
			}
		
			// Handle case when target is a string or something (possible in deep copy)
			if ( typeof target !== "object" && !jQuery.isFunction(target) )
				target = {};
		
			// extend jQuery itself if only one argument is passed
			if ( length == i ) {
				target = this;
				--i;
			}
		
			for ( ; i < length; i++ )
				// Only deal with non-null/undefined values
				if ( (options = arguments[ i ]) != null )
					// Extend the base object
					for ( var name in options ) {
						var src = target[ name ], copy = options[ name ];
		
						// Prevent never-ending loop
						if ( target === copy )
							continue;
		
						// Recurse if we're merging object values
						if ( deep && copy && typeof copy === "object" && !copy.nodeType )
							target[ name ] = jQuery.extend( deep, 
								// Never move original objects, clone them
								src || ( copy.length != null ? [ ] : { } )
							, copy );
		
						// Don't bring in undefined values
						else if ( copy !== undefined )
							target[ name ] = copy;
		
					}
		
			// Return the modified object
			return target;
		};

})(jQuery);	